#!/usr/bin/env python

'''
zbdump - a tcpdump-like tool for ZigBee/IEEE 802.15.4 networks

Compatible with Wireshark 1.1.2 and later - jwright@willhackforsushi.com
The -p flag adds CACE PPI headers to the PCAP - rmspeers@gmail.com
'''

import sys
import signal
from killerbee import *

def usage():
    print >>sys.stderr, """
zbdump - a tcpdump-like tool for ZigBee/IEEE 802.15.4 networks

Usage: zbdump [-fiwDchp] [-f channel] [-w pcapfile] [-W daintreefile] 
         [-i devnumstring] [-p] [-g serial_dev_to_ignore]
    """

def interrupt(signum, frame):
    global packetcount
    global kb
    global pd
    global dt
    kb.sniffer_off()
    kb.close()
    if pd:
        pd.close()
    if dt:
        dt.close()
    print "%d packets captured" % packetcount
    sys.exit(0)

# PcapDumper, only used if -w is specified
pd = None
# DainTreeDumper, only used if -W is specified
dt = None

# Command-line arguments
arg_channel = None
arg_pcapsavefile = None
arg_dsnasavefile = None
arg_devstring = None
arg_count = -1
arg_ppi = False
arg_gpsstring = None

# Global
packetcount = 0

while len(sys.argv) > 1:
    op = sys.argv.pop(1)
    if op == '-f':
        arg_channel = int(sys.argv.pop(1))
    elif op == '-w':
        arg_pcapsavefile = sys.argv.pop(1)
    elif op == '-W':
        arg_dsnasavefile = sys.argv.pop(1)
    elif op == '-g':
        arg_gpsstring = sys.argv.pop(1)
    elif op == '-i':
        arg_devstring = sys.argv.pop(1)
    elif op == '-h':
        usage()
        sys.exit(0)
    elif op == '-D':
        show_dev()
        sys.exit(0)
    elif op == '-c':
        arg_count = int(sys.argv.pop(1))
    elif op == '-p':
        arg_ppi = True
 
if arg_channel == None:
    print >>sys.stderr, "ERROR: Must specify a channel with -f"
    usage()
    sys.exit(1)
elif arg_channel < 11 or arg_channel > 26:
    print >>sys.stderr, "ERROR: Must specify a valid IEEE 802.15.4 channel between 11 and 26."
    sys.exit(1)
rf_freq_mhz = (arg_channel - 10) * 5 + 2400

if arg_pcapsavefile == None and arg_dsnasavefile == None:
    print >>sys.stderr, "ERROR: Must specify a savefile with -w (libpcap) or -W (Daintree SNA)"
    usage()
    sys.exit(1)

if (arg_pcapsavefile != None):
    pd = PcapDumper(DLT_IEEE802_15_4, arg_pcapsavefile, ppi=arg_ppi)
if (arg_dsnasavefile != None):
    dt = DainTreeDumper(arg_dsnasavefile)

kb = KillerBee(device=arg_devstring, gps=arg_gpsstring)
signal.signal(signal.SIGINT, interrupt)

kb.set_channel(arg_channel)
kb.sniffer_on()

print "zbdump: listening on \'%s\', link-type DLT_IEEE802_15_4, capture size 127 bytes" % kb.get_dev_info()[0]

while arg_count != packetcount:
    packet = kb.pnext()
    # packet[1] is True if CRC is correct, check removed to have promiscous capture regardless of CRC
    if packet != None: # and packet[1]:
        packetcount+=1
        if pd:
            pd.pcap_dump(packet['bytes'], ant_dbm=packet['dbm'], freq_mhz=rf_freq_mhz)
        if dt:
            dt.pwrite(packet['bytes'])

kb.sniffer_off()
kb.close()
if pd:
    pd.close()
if dt:
    dt.close()

print "%d packets captured" % packetcount
